/**
 * n-grid
 * author: 'byhgj'
 * git: https://gitee.com/byhgj/n-grid.git
 */
class nGrid {
	constructor(opts){
		let config = Object.assign({
			hideTitle: false,
			selectable: false,
			multiSelect: false,
			//backgroundColor: '#f6f6f6',
			//theadBackgroundColor: '#f6f6f6',
			tbodyBackgroundColor: 'white',
			idx: 'id'
		}, opts.config);
		
		let ntable = document.querySelector(opts.el);
		ntable.setAttribute('class', 'n-table');
		if (config.backgroundColor) ntable.style.backgroundColor = config.backgroundColor;
		
		// tthead
		let thead = document.createElement('div');
		thead.setAttribute('class', 'thead');
		let _scrollbarWidth = this._getScrollbarWidth();
		thead.style.width = `calc(100% - ${_scrollbarWidth}px)`;
		if (config.hideTitle) thead.style.height = 0;
		if (config.theadBackgroundColor) thead.style.backgroundColor = config.theadBackgroundColor;

		let thead_table = document.createElement('table');
		let tr = document.createElement('tr');
		for(let col of opts.cols) {
			let td = document.createElement('td');
			td.innerHTML = col.title||col.index;
			td.style.width = td.style.minWidth = td.style.maxWidth = col.width + 'px';
			td.style.display = col.hidden?'none':'';
			tr.append(td);
		}
		thead_table.append(tr);

		thead.append(thead_table);
		document.querySelector(opts.el).append(thead);

		// tbody
		let tbody = document.createElement('div');
		tbody.setAttribute('class', 'tbody');
		tbody.style.height = `calc(100% - ${thead.offsetHeight}px)`;
		if (config.tbodyBackgroundColor) tbody.style.backgroundColor = config.tbodyBackgroundColor;

		let tbody_table = document.createElement('table');

		tbody.append(tbody_table);
		document.querySelector(opts.el).append(tbody);
	
		tbody.addEventListener('scroll', function(){
			thead.scrollLeft = tbody.scrollLeft;
		})
	
		this.config = config;
		this.opts = opts;
		this.thead = thead;
		this.tbody = tbody;
		this.thead_table = thead_table;
		this.tbody_table = tbody_table;

		if (opts.data) this.loadData(opts.data);

	}
	_getScrollbarWidth() {
		let oP = document.createElement('p'),
			styles = {
				width: '100px',
				height: '100px',
				overflowY: 'scroll'
			}, i, scrollbarWidth;
		for (i in styles) oP.style[i] = styles[i];
		document.body.appendChild(oP);
		scrollbarWidth = oP.offsetWidth - oP.clientWidth;
		oP.remove();
		return scrollbarWidth;
	}
	loadData(data){
		this.data = data;
		let self = this;
		let tbody_table = this.tbody_table;
		tbody_table.innerHTML = '';
		for(let i=0; i<data.length; i++){
			let tr = document.createElement('tr');
			if (this.config.idx && data[i][this.config.idx])
				tr.setAttribute('idx', data[i][this.config.idx]);
			if (typeof this.opts.rowStyle === 'function') {
				let _class = this.opts.rowStyle(data[i]);
				if (_class) tr.setAttribute('class', _class);
			}
			for(let j in this.opts.cols){
				j = parseInt(j);
				let col = this.opts.cols[j];
				let td = document.createElement('td');
				if (col.type === 'calc') td.innerHTML = col['content'];
				else td.innerHTML = data[i][col.index];

				let align = (col.align||'').trim();
				if (align != '') td.style.textAlign = align;

				td.style.width = td.style.minWidth = td.style.maxWidth = col.width + 'px';
				td.style.display = col.hidden?'none':'';

				// events
				if (this.opts.events && typeof this.opts.events['cellclick'] === 'function')
					td.addEventListener('click', function(){
						if (self.config.selectable) {
							if (!self.config.multiSelect)
								self.tbody_table.querySelectorAll('.selected').forEach(obj => {obj.classList.remove('selected')});
							tr.classList.toggle('selected');
						}
						self.opts.events['cellclick'](data[i], (col.type === 'calc') ? '' : data[i][col.index], tr, td);
					})
	
				if (this.opts.events && typeof this.opts.events['celldblclick'] === 'function')
					td.addEventListener('dblclick', function(){
						self.opts.events['celldblclick'](data[i], (col.type === 'calc') ? '' : data[i][col.index], tr, td);
					})

				if (this.opts.events && typeof this.opts.events['popup'] === 'function')
					td.addEventListener('contextmenu', function(){
						if (self.config.selectable) {
							if (!self.config.multiSelect)
								self.tbody_table.querySelectorAll('.selected').forEach(obj => {obj.classList.remove('selected')});
							tr.classList.toggle('selected');
						}
						self.opts.events['popup'](data[i], (col.type === 'calc') ? '' : data[i][col.index], tr, td);
						return false;
					})
				if (this.opts.events && typeof this.opts.events['cellenter'] === 'function')
					td.addEventListener('mouseenter', function(){
						self.opts.events['cellenter'](data[i], (col.type === 'calc') ? '' : data[i][col.index], tr, td);
					})
				if (this.opts.events && typeof this.opts.events['cellleave'] === 'function')
					tr.addEventListener('mouseleave', function(){
						self.opts.events['cellleave'](data[i], (col.type === 'calc') ? '' : data[i][col.index], tr, td);
					})

				tr.append(td);
			}
			if (this.opts.events && typeof this.opts.events['rowclick'] === 'function')
				tr.addEventListener('click', function(){
					if (self.config.selectable) {
						if (!self.config.multiSelect)
							self.tbody_table.querySelectorAll('.selected').forEach(obj => {obj.classList.remove('selected')});
						tr.classList.toggle('selected');
					}
					self.opts.events['rowclick'](data[i], tr);
				})

			if (this.opts.events && typeof this.opts.events['rowdblclick'] === 'function')
				tr.addEventListener('dblclick', function(){
					self.opts.events['rowdblclick'](data[i], tr);
				})
			tbody_table.append(tr);
		}
		return this;
	}
	appendData(data){
		this.loadData(this.data.concat(data));
		return this;
	}
	_eq(a,b){
		let _a = Object.keys(a), _b = Object.keys(b);
		if (_a.length != _b.length) return false;
		for(let i=0;i<_a.length;i++){
			if (a[_a[i]] != b[_b[i]]) return false;
		}
		return true;
	}
	removeData(data){
		for(let i=0;i<data.length;i++){
			let item = data[i];
			let idx = item[this.config.idx];
			this.tbody.querySelector(`tr[idx="${idx}"]`).remove();

			for(let j=0;j<this.data.length;j++){
				if (this._eq(item, this.data[j])) this.data.splice(j,1);
			}
		}
		return this;
	}
}

(function(){
	window.ngrid = function(opts){
		return new nGrid(opts);
	}
})();